package clustering;

import static preprocess.XMLContracter.ATTRIBUTE;
import static preprocess.XMLContracter.NESTING;
import static preprocess.XMLContracter.REPETITION;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;

import preprocess.XMLContracter;
import preprocess.XMLDoc;
import similarity.AverageSimilarity;
import similarity.MixSimilarity;
import similarity.Similarity;
import similarity.SimpleTEDSimilarity;
import similarity.TextSimilarity;
import utils.CategoriesInfo;
import utils.Configuration;
import classification.calcSimilarity.CalcSimilarityBySLVM;

public class ClusteringTest
{
    public static HashSet<String> fileNameSet = new HashSet<String>();
    public static String          separateLine;
    static
    {
        separateLine = "";
        for (int i = 0; i < 40; i++)
        {
            separateLine += "+-";
        }
    }

    public static List<XMLDoc> getDocs() throws IOException
    {
        final SAXReader reader = new SAXReader();
        File root = new File(Configuration.DataSetPath);
        List<XMLDoc> list = new ArrayList<XMLDoc>();
        XMLContracter con = new XMLContracter();
        Set<File> xmls = new HashSet<File>();
        getAllXMLFiles(root, xmls);
        Random rand = new Random();
        for (File xml : xmls)
        {
            try
            {
                Document doc = reader.read(xml);
                doc = con.contract(doc, NESTING | REPETITION | ATTRIBUTE);
                String name = xml.getName();
                name = name.substring(0, name.length() - 4);
                fileNameSet.add(name);
                XMLDoc xmldoc = new XMLDoc(doc, name);
                int index = rand.nextInt(list.size() + 1);
                list.add(index, xmldoc);
            }
            catch (Exception e)
            {
                System.out.println("parse error: " + xml.getAbsolutePath());
            }
        }
        return list;
    }

    private static void getAllXMLFiles(File dir, Set<File> set)
    {
        for (File file : dir.listFiles())
        {
            if (file.isDirectory())
                getAllXMLFiles(file, set);
            else if (file.getName().toLowerCase().endsWith(".xml"))
                set.add(file);
        }
    }

    public static List<XMLDoc> getDocsWithoutProcess() throws IOException
    {
        final SAXReader reader = new SAXReader();
        File root = new File(Configuration.DataSetPath);
        List<XMLDoc> list = new ArrayList<XMLDoc>();
        XMLContracter con = new XMLContracter();
        Set<File> xmls = new HashSet<File>();
        getAllXMLFiles(root, xmls);
        Random rand = new Random();
        for (File xml : xmls)
        {
            try
            {
                Document doc = reader.read(xml);
                doc = con.contract(doc, NESTING | REPETITION | ATTRIBUTE);
                String name = xml.getName();
                name = name.substring(0, name.length() - 4);
                fileNameSet.add(name);
                XMLDoc xmldoc = new XMLDoc(name);
                xmldoc.setDoc(doc);
                int index = rand.nextInt(list.size() + 1);
                list.add(index, xmldoc);
            }
            catch (Exception e)
            {
                System.out.println("parse error: " + xml.getAbsolutePath());
            }
        }
        return list;
    }

    public static void main(String[] args) throws DocumentException,
            IOException, ClassNotFoundException
    {
        double start = System.currentTimeMillis();
        List<XMLDoc> list = getDocs();
        CategoriesInfo factInfo = new CategoriesInfo(new File(
                Configuration.DataSetPath));
        CategoriesInfo testInfo = null;
        for (HashSet<String> set : factInfo.getCategoriesMap().values())
        {
            String[] array = set.toArray(new String[0]);
            for (String name : array)
            {
                if (!fileNameSet.contains(name))
                    set.remove(name);
            }
        }
        Clustering clu = null;
        List<List<XMLDoc>> result = null;
        int count = new Integer(Configuration.CLUSTERING.ClusterCount);
        Similarity[] simArray = { new SimpleTEDSimilarity(),
                new TextSimilarity(), new MixSimilarity(),
                new AverageSimilarity(), new CalcSimilarityBySLVM() };
        BufferedWriter writer = new BufferedWriter(new FileWriter(
                "./cluster result.txt", true));
        writer.append(separateLine).append("\r\nclustering on direction:")
                .append(Configuration.DataSetPath).append("\r\n");
        writer.flush();
        for (Similarity sim : simArray)
        {
            writer.append("\r\nsimilarity model:").append(
                    ((Object) sim).getClass().getName()).append("\r\n");
            double result1, result2;

            writer.append("\tclustering algorithm: K-Means\r\n");
            writer.flush();
            clu = new K_MeansClustering(sim);
            result = clu.cluster(list, count);
            testInfo = clu.toCategoriesInfo(result);
            for (List<XMLDoc> li : result)
            {
                writer.append("\t\t").append("" + li.size()).append("##")
                        .append(li.toString()).append("\r\n");
                writer.flush();
            }
            result1 = testInfo.evaluateWith(factInfo);
            result2 = factInfo.evaluateWith(testInfo);
            writer.append("\t\t").append("" + result1).append("\r\n");
            writer.append("\t\t").append("" + result2).append("\r\n");
            writer.append("\t\t").append("" + (result1 + result2) / 2).append(
                    "\r\n");
            writer.flush();

            writer.append("\tclustering algorithm: Hierarchy\r\n");
            clu = new HierarchyClustering(sim);
            result = clu.cluster(list, count);
            testInfo = clu.toCategoriesInfo(result);
            for (List<XMLDoc> li : result)
            {
                writer.append("\t\t").append("" + li.size()).append("##")
                        .append(li.toString()).append("\r\n");
                writer.flush();
            }
            result1 = testInfo.evaluateWith(factInfo);
            result2 = factInfo.evaluateWith(testInfo);
            writer.append("\t\t").append("" + result1).append("\r\n");
            writer.append("\t\t").append("" + result2).append("\r\n");
            writer.append("\t\t").append("" + (result1 + result2) / 2).append(
                    "\r\n");
            writer.flush();
        }
        double total = System.currentTimeMillis() - start;
        writer.append("total time:" + (total / 1000) + "s").append("\r\n");
        writer.flush();
        writer.close();
    }
}
